package io.github.loserya.utils;

import io.github.loserya.core.entity.UpdateField;
import io.github.loserya.core.wrapper.LambdaQueryWrapper;
import org.springframework.data.mongodb.core.query.Update;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Objects;

public class BaseMapperUtil {

    private BaseMapperUtil() {
    }

    /**
     * 通过条件构建
     */
    public static Update getUpdate(LambdaQueryWrapper<?> queryWrapper) {

        Update update = new Update();
        List<UpdateField> updateFields = queryWrapper.getCondition().getUpdateFields();
        if (CollectionUtils.isEmpty(updateFields)) {
            throw ExceptionUtils.mpe("update field is empty");
        }
        updateFields.forEach(item -> {
            switch (item.getType()) {
                case INCR:
                    update.inc(item.getCol(), (Number) item.getVal());
                    break;
                case DECR:
                    update.inc(item.getCol(), negate((Number) item.getVal()));
                    break;
                default:
                    update.set(item.getCol(), item.getVal());
            }
        });
        return update;

    }

    /**
     * 取反
     */
    public static Number negate(Number number) {

        if (number instanceof Integer) {
            return -number.intValue();
        } else if (number instanceof Double) {
            return -number.doubleValue();
        } else if (number instanceof Float) {
            return -number.floatValue();
        } else if (number instanceof Long) {
            return -number.longValue();
        } else if (number instanceof Short) {
            return -number.shortValue();
        } else if (number instanceof Byte) {
            return -number.byteValue();
        } else {
            throw ExceptionUtils.mpe("Unsupported number type: " + number.getClass());
        }

    }

    /**
     * 通过反射获取需要更新的字段
     */
    public static Update getUpdateByEntity(Object entity) {

        Update update = new Update();
        Class<?> aClass = entity.getClass();
        bind(entity, update, aClass);
        return update;

    }

    public static void bind(Object entity, Update update, Class<?> aClass) {

        if (Object.class.equals(aClass)) {
            return;
        }
        for (Field field : aClass.getDeclaredFields()) {
            try {
                field.setAccessible(true);
                Object result = field.get(entity);
                if (Objects.nonNull(result)) {
                    update.set(field.getName(), result);
                }
            } catch (Exception ignore) {
            }
        }
        bind(entity, update, aClass.getSuperclass());

    }

}
